/*
 * @Author: yangzonglong
 * @Date: 2021-03-18 13:45:41
 * @version: v1.0.0
 * @Descripttion: 显示表单
 * @LastEditors: 871387321@qq.com 871387321@qq.com
 * @LastEditTime: 2023-10-28 13:15:03
 * @Auditor:
 */
import React, { useImperativeHandle, forwardRef, useEffect, useRef, useState, useMemo } from 'react';
import { Form } from 'antd';
import { RuleObject } from 'antd/lib/form';
import Qs from 'query-string';
import moment from 'moment';
import { controlMap, ControlType } from './../config';
import { tableIdToName, includesControl, getActionFiled, } from './util';
import { flatControl } from '../util';
import evalScript, { appendFormChild, removeFormChild, es6ToEs5 } from './../eval';
import { ColumnType } from './../components/table/config';
import { ViewProps, ControlProps, ViewRefProps, ControlRefProps, ActionFieldType, AppendFormChildConfigsType, NextResultType, ShowModalOptionsType } from './../interface';
import ModalForm, { ModalFormRef } from './ModalForm';
import ModalError, { ModalErrorRef } from './ModalError';
import './view.scss';

const rules = [{ required: true }];
const clearFlag = 'clearFlag'; //   是否需要 清 combox的值
const linkFiledType = ['input', 'inputNumber', 'textArea'], //能关联数据联动的控件类型 格式为关联组件和显示字段;
  linkQueryType = ['dataLinkComBox']; //能关联数据联动的控件类型 格式为query联动 不直接赋值;

const eventsMap = {};

const View = ({
  data,
  structure,
  disabled,
  editFields,
  hideFields,
  formatFormBtns,
  setFooter,
  showPageHeaderBtn,
  business,
  parentNext
}: ViewProps, ref: React.Ref<ViewRefProps>) => {
  const [form] = Form.useForm();
  const controlRefs = useRef<Record<string, ControlRefProps>>({}); // 控件ref集合
  const interceptors = useRef({}); // 请求拦截器
  const modalFormRef = useRef<ModalFormRef>(null);
  const scriptsChangeDataRef = useRef({}); // 记录scriptsChangeData，立即可拿到最新的值
  const [scriptsChangeData, _setScriptsChangeData] = useState<any>({});
  const [controlExtraOptions, setControlExtraOptions] = useState<ActionFieldType>({}); // 脚本额外控制控件
  const [structureList, setStructureList] = useState<ControlProps[]>([]);
  const [loadScript, setLoadScript] = useState({ url: '', scriptText: '' });
  const [isRender, setIsRender] = useState(false);

  const loadScriptRef = useRef({ url: '', scriptText: '' }); // 存储script load脚本，代码里使用的都是本对象
  const loadScriptTimer = useRef<number | null>(null); // loadscript延时器，避免短暂重复执行
  const cacheFiledList = useRef({});
  const cacheLovList = useRef({});
  const cacheTableList = useRef({});
  const cacheQueryList = useRef({});
  const linkFiledList = useRef<string[]>([]);
  const linkLovList = useRef<string[]>([]);
  const linkTableList = useRef<string[]>([]);
  const linkQueryList = useRef<string[]>([]);
  const selectNameList = useRef<string[]>([]);
  const originalColumns = useRef<Record<string, ColumnType[]>>({});
  const modalErrorRef = useRef<ModalErrorRef>(null);

  const href = window.location.href;
  const query = useMemo(() => Qs.parseUrl(href).query, [href]);
  const isImplementLoadScript = useRef(false); // 是否执行过load脚本，避免因为依赖问题重复执行
  const beforeScript = useRef('');

  useEffect(() => {
    if (structure.list) {
      setStructureList(structure.list);
      setControlExtraOptions({});
      interceptors.current = {};
      isImplementLoadScript.current = false;
      setIsRender(false);
    }
  }, [structure.list]);

  useEffect(() => {
    cacheFiledList.current = {};

    const flatStructureList = flatControl(structureList || []);

    flatStructureList.forEach((item) => {

      if (item?.options?.textAreaProps) {
        item.options.inputProps = item.options.textAreaProps;
      }

      if (item.type === ControlType.SELECT) {
        selectNameList.current.push(item.options?.formItemProps?.name);
      }

      if (linkFiledType.includes(item.type) && item?.options?.inputProps?.bindName && item?.options?.inputProps?.showFiled) {

        if (cacheFiledList.current[item?.options?.inputProps?.bindName]) {
          cacheFiledList.current[item?.options?.inputProps?.bindName].push({
            name: item.options?.formItemProps?.name,
            showFiled: item?.options?.inputProps?.showFiled,
          });
        } else {
          cacheFiledList.current[item?.options?.inputProps?.bindName] = [
            { name: item.options?.formItemProps?.name, showFiled: item?.options?.inputProps?.showFiled },
          ];
        }
      }

      else if (linkQueryType.includes(item.type)) {

        const bindName = item?.options?.inputProps?.bindName;


        if (bindName) {
          if (cacheQueryList.current[bindName]) {
            cacheQueryList.current[bindName].push({
              name: item.options?.formItemProps?.name,
            });
          } else {
            cacheQueryList.current[bindName] = [{ name: item.options?.formItemProps?.name }];
          }
        }

      }

      else if (item.type === 'dataLink') {

        const bindName = item?.options?.inputProps?.bindName;
        if (!bindName) return;

        if (cacheLovList.current[item?.options?.inputProps?.bindName]) {
          cacheLovList.current[item?.options?.inputProps?.bindName].push({
            name: item.options?.formItemProps?.name,
          });
        } else {
          cacheLovList.current[item?.options?.inputProps?.bindName] = [{ name: item.options?.formItemProps?.name }];
        }
      }

      else if (item.type === 'table') {
        const columns = item?.options?.tableProps.columns || [];

        columns.forEach((element: any) => {
          if (!element?.options.bindName) return;
          if (cacheTableList.current[element?.options.bindName]) {
            cacheTableList.current[element?.options.bindName].push({
              name: element.dataIndex,
            });
          } else {
            cacheTableList.current[element?.options.bindName] = [{ name: element.dataIndex }];
          }
        });
      }


    });

    linkFiledList.current = Object.keys(cacheFiledList.current);
    linkQueryList.current = Object.keys(cacheQueryList.current);
    linkLovList.current = Object.keys(cacheLovList.current);
    linkTableList.current = Object.keys(cacheTableList.current);

  }, [structureList]);

  useEffect(() => {
    if (!structure.list) return;

    setControlExtraOptions(prev => {
      const fieldsMap = {};

      hideFields?.forEach(item => {
        const k = tableIdToName(item, structure.list)!;

        if (!fieldsMap[k]) fieldsMap[k] = {};
        fieldsMap[k].hide = true;
      });

      editFields?.forEach(item => {
        const k = tableIdToName(item, structure.list)!;

        if (!fieldsMap[k]) fieldsMap[k] = {};
        fieldsMap[k].disabled = false;
      });

      return {
        ...fieldsMap,
        ...prev
      };
    });
  }, [editFields, hideFields, structure.list]);

  useEffect(() => {
    setScriptsChangeData(data, true);
    form.resetFields();
    form.setFieldsValue(data);

    const fieldsValue = {};

    structure.list?.forEach(item => {
      if (item.options?.formItemProps?.name?.includes('.')) {
        const arr = item.options.formItemProps.name.split('.');
        fieldsValue[item.options.formItemProps.name] = data?.[arr[0]]?.[arr[1]];
      }
    });

    if (Object.keys(fieldsValue).length) {
      form.setFieldsValue(fieldsValue);
    }
  }, [data, form, structure.list]);

  useEffect(() => {
    const tableColumnsRequired = {};

    for (const k in controlExtraOptions) {
      if (k.includes('#')) {
        const arr = k.split('#');
        if (!tableColumnsRequired[arr[0]]) tableColumnsRequired[arr[0]] = {};
        tableColumnsRequired[arr[0]][arr[1]] = controlExtraOptions[k].required;
      }
    }

    for (const ref in controlRefs.current) {
      if (controlRefs.current[ref]?.setTableRequired) {
        controlRefs.current[ref].setTableRequired?.(controlExtraOptions[ref]?.required, tableColumnsRequired[ref]);
      }
    }
  }, [controlExtraOptions]);

  function setScriptsChangeData(scriptChangeData: any, reset?: boolean) {
    if (reset) {
      scriptsChangeDataRef.current = scriptChangeData;
      _setScriptsChangeData(scriptChangeData);
    } else {
      scriptsChangeDataRef.current = { ...scriptsChangeDataRef.current, ...scriptChangeData };
      _setScriptsChangeData(scriptsChangeDataRef.current);
    }
  }

  const getRefs = () => {
    const refsKey = Object.keys(controlRefs.current!);
    const refDataList: any = [];

    flatControl(structureList).forEach(item => {
      const id = item.options?.formItemProps?.name || item.options?.name || item.id;
      refDataList[id] = {};
    });

    if (refsKey.length) {
      for (let item of refsKey) {
        if (controlRefs?.current[item]?.onListRefresh) {
          refDataList.push(controlRefs?.current[item]);
        }
        refDataList[item] = controlRefs?.current[item];
      }
    }

    return refDataList;
  };

  const Events = useMemo(() => {
    return {
      on: (eventName: string, handler: Function) => {
        eventsMap[eventName] = handler;
      },

      trigger: (eventName: string, data: any) => {
        if (eventsMap[eventName]) eventsMap[eventName](data);
      }
    };
  }, []);

  // 脚本分组
  const [scriptsChange, scriptsSubmit, scriptsInterceptors] = useMemo(() => {
    loadScriptRef.current = { url: '', scriptText: '' };

    const changes: string[] = [],
      loads: string[] = [],
      submits: string[] = [],
      interceptors: string[] = [];

    structure.list?.forEach(item => {
      if (item.options?.scriptText) {
        if (item.type === ControlType.SCRIPT_CHANGE) {
          changes.push(es6ToEs5(item.options.scriptText));
        }

        if (item.type === ControlType.SCRIPT_LOAD) {
          loads.push(es6ToEs5(item.options.scriptText));
        }

        if (item.type === ControlType.SCRIPT_SUBMIT) {
          submits.push(es6ToEs5(item.options.scriptText));
        }

        if (item.type === ControlType.SCRIPT_INTERCEPTORS) {
          interceptors.push(item.options.scriptText);
        }

        if (item.type === ControlType.SCRIPT_BEFORE) {
          beforeScript.current = item.options.scriptText;
        }
      }
    });

    loadScriptRef.current = {
      url: window.location.href,
      scriptText: loads[0]
    };

    setLoadScript({
      url: window.location.href,
      scriptText: loads[0]
    });

    return [changes, submits, interceptors];
  }, [structure.list]);

  useImperativeHandle(ref, () => ({
    ...form,
    validateFields
  }));

  useEffect(() => {
    if (scriptsInterceptors.length) {
      evalScript({
        scriptText: scriptsInterceptors[0],
        extra: {
          _OBJ1_: scriptsChangeData,
          _ENV_: structure.enviromentConfig || {},
          _BUSINESS_: business,
          parentNext: (result: NextResultType) => parentNext?.(result)
        },
        next: (result: NextResultType) => {
          interceptors.current = result;
        }
      });
    }
  }, [scriptsInterceptors, business, scriptsChangeData, parentNext, structure.enviromentConfig]);

  // load scripts
  useEffect(() => {
    if (isImplementLoadScript.current || structure.list?.length === 0) return;

    if (loadScript.url === window.location.href) {
      if (loadScriptRef.current.scriptText) {
        if (loadScriptTimer.current) {
          window.clearTimeout(loadScriptTimer.current);
          loadScriptTimer.current = null;
        }

        loadScriptTimer.current = window.setTimeout(() => {
          // before脚本存在，需执行完再执行load脚本
          if (beforeScript.current) {
            evalScript({
              scriptText: beforeScript.current,
              extra: {
                _ENV_: structure.enviromentConfig || {},
                _OBJ_: data || {},
                _OBJ1_: data,
                _QUERY_: query,
                _PRINT_: false,
                _BUSINESS_: business, // 上层业务注入信息
                showMessage: modalErrorRef.current?.show
              },
              next: ((result: NextResultType, actionFiled: ActionFieldType) => {
                if (actionFiled) setControlExtraOptions(prev => ({ ...prev, ...actionFiled }));
                _loadFn(result);
              })
            });
          } else {
            _loadFn();
          }

          function _loadFn(beforeObj?: object) {
            const _REFS_: any = getRefs();

            flatControl(structure.list).forEach(item => {
              const id = item.options?.formItemProps?.name || item.options?.name || item.id;
              _REFS_[id] = {};
            });

            Object.defineProperty(_REFS_, '0', {
              get: () => {
                const _REFS_ = getRefs();
                return _REFS_[0];
              }
            });

            for (let ref in _REFS_) {
              Object.defineProperty(_REFS_, ref, {
                get: () => {
                  const _REFS_ = getRefs();
                  return _REFS_[ref];
                }
              });
            }

            isImplementLoadScript.current = true;
            setIsRender(true);

            if (beforeObj) Object.assign(data!, beforeObj);

            evalScript({
              scriptText: loadScriptRef.current.scriptText,
              extra: {
                _REFS_,
                _EVENTS_: Events,
                _ENV_: structure.enviromentConfig || {},
                _OBJ_: data,
                _OBJ1_: data,
                _QUERY_: query,
                _PRINT_: false,
                _BUSINESS_: business, // 上层业务注入信息
                showMessage: modalErrorRef.current?.show,
                appendFormChild: (formName: string, configs: AppendFormChildConfigsType) => {
                  appendFormChild(
                    formName,
                    structure.list,
                    configs.pre,
                    (newStructureList: ControlProps[]) => {
                      setStructureList(newStructureList);
                      emitControlChangeValue();
                      if (configs.next) configs.next();
                    }
                  );
                },

                parentNext: (result: NextResultType) => parentNext?.(result)
              },
              next: ((result: NextResultType, actionFiled: ActionFieldType) => {
                if (actionFiled) {
                  setControlExtraOptions(prev => {
                    return { ...prev, ...actionFiled };
                  });
                }

                setScriptsChangeData({ ...data, ...result });
                emitControlChangeValue();
              })
            }, true);
          }
        }, 600);
      } else {
        if (beforeScript.current) {
          evalScript({
            scriptText: beforeScript.current,
            extra: {
              _ENV_: structure.enviromentConfig || {},
              _OBJ_: data || {},
              _OBJ1_: data,
              _QUERY_: query,
              _PRINT_: false,
              _BUSINESS_: business, // 上层业务注入信息
              showMessage: modalErrorRef.current?.show
            },
            next: ((result: NextResultType, actionFiled: ActionFieldType) => {
              if (actionFiled) setControlExtraOptions(prev => ({ ...prev, ...actionFiled }));
              setScriptsChangeData({ ...data, ...result });
              emitControlChangeValue();

              isImplementLoadScript.current = true;
              setIsRender(true);
            })
          });
        } else {
          loadScriptTimer.current = window.setTimeout(() => {
            isImplementLoadScript.current = true;
            setIsRender(true);
          }, 200);
        }
      }
    }
    // eslint-disable-next-line
  }, [loadScript, data, form, query, Events, business, structure.list, structure.enviromentConfig]);

  // 执行change scripts
  async function implementScriptsChange(changeValue: any, tableChangeValue?: any) {
    if (scriptsChange.length) {
      const _REFS_ = getRefs();
      evalScript({
        scriptText: scriptsChange[0],
        extra: {
          validateRequired,
          _REFS_,
          _ENV_: structure.enviromentConfig || {},
          _EVENTS_: Events,
          _OBJ_: tableChangeValue || changeValue,
          _OBJ1_: scriptsChangeDataRef.current,
          _QUERY_: query,
          _BUSINESS_: business,
          showMessage: modalErrorRef.current?.show,

          appendFormChild: (formName: string, configs: AppendFormChildConfigsType) => {
            appendFormChild(
              formName,
              configs?.reset ? structure.list : structureList,
              configs.pre,
              (list: ControlProps[]) => {
                setStructureList(list);
                if (configs.next) configs.next();
              }
            );
          },

          removeFormChild: (formName?: string) => {
            const [newStructureList, removeChildIdMap] = removeFormChild(structureList, formName);

            setStructureList(newStructureList as ControlProps[]);
            form.setFieldsValue(removeChildIdMap);
          }
        },
        next: (result: NextResultType, actionFiled: ActionFieldType, next?: Function) => {
          if (actionFiled) setControlExtraOptions(prev => ({ ...prev, ...actionFiled }));

          const newScriptsChangeData = { ...scriptsChangeDataRef.current, ...result };
          setScriptsChangeData(newScriptsChangeData);

          if (actionFiled) {
            setTimeout(() => {
              emitControlChangeValue();
            }, 0);
          } else {
            emitControlChangeValue();
          }

          if (next) {
            setTimeout(() => {
              next(getRefs());
            }, 200);
          }
        }
      }, true);
    }
  }

  // 提供给业务脚本校验必填项
  function validateRequired(checkHideItem = true) {
    const values = { ...scriptsChangeDataRef.current };
    const unfilled = structureList.some(item => {
      if (!item.options?.formItemProps?.name) return false;
      const value = values[item.options?.formItemProps?.name];

      if (!checkHideItem) {
        const currActionFiled = getActionFiled(controlExtraOptions, item);

        if (typeof currActionFiled.hide === 'boolean') {
          if (currActionFiled.hide) {
            if (currActionFiled.hideExcludes) {
              if (!includesControl(currActionFiled.hideExcludes, item)) return false;
            } else return false;
          } else {
            if (currActionFiled.hideExcludes && includesControl(currActionFiled.hideExcludes, item)) return false;
          }
        }
      }

      return item.options?.formItemProps?.required
        && (typeof value === 'undefined' || value === null || value === '');
    });

    if (unfilled) return false;

    const refsKey = Object.keys(controlRefs.current);
    if (refsKey.length) {
      for (let item of refsKey) {
        const fn = controlRefs.current[item]?.getData;

        if (fn) {
          const data = fn();
          // 子组件校验出错，抛出错误
          if (data === false) return false;
          values[item] = data;
        }
      }
    }

    return true;
  }

  async function validateFields(required = true, options?: object, executeSubmitScript = true) {
    let values: any = { ...scriptsChangeDataRef.current };

    if (required) {
      try {
        await form.validateFields();
      } catch (error: any) {
        const firstErrorName = error.errorFields[0]?.name;

        if (firstErrorName) {
          let currDom: HTMLElement | null = document.getElementById(firstErrorName);
          const formErrorScrollBox = document.getElementById('FORM_ERROR_SCROLL');

          if (currDom && formErrorScrollBox) {
            let offsetTop = 0;

            while (currDom) {
              offsetTop += currDom.offsetTop;

              if (currDom.offsetParent && currDom.offsetParent === formErrorScrollBox) {
                currDom = null;
              } else {
                currDom = currDom.offsetParent as HTMLElement;
              }
            }

            if (offsetTop > formErrorScrollBox.offsetHeight) {
              formErrorScrollBox.scrollTo({ top: offsetTop - 40 });
            }
          }
        }
        throw error;
      }

      const refsKey = Object.keys(controlRefs.current);

      if (refsKey.length) {
        for (let item of refsKey) {
          const fn = controlRefs.current[item]?.getData;

          if (fn) {
            const data = await fn('view');

            // 子组件校验出错，抛出错误
            if (data === false) return false;

            values[item] = data;
          }
        }
      }
    } else {
      const refsKey = Object.keys(controlRefs.current);

      if (refsKey.length) {
        for (let item of refsKey) {

          const getDataNotCheckFn = controlRefs.current[item]?.getDataNotCheck;
          const getDataFn = controlRefs.current[item]?.getData;

          if (getDataNotCheckFn || getDataFn) {
            const data = await (getDataNotCheckFn || getDataFn)!('view');
            values[item] = data;
          }
        }
      }
    }

    // a.b 需要转换
    // 需要记录转换的字段，在待办事项场景里使用
    const _transform = {};
    for (let k in values) {
      if (k.includes('.')) {
        const arr = k.split('.');
        if (!values[arr[0]]) values[arr[0]] = {};
        values[arr[0]][arr[1]] = values[k];
        delete values[k];
        _transform[arr[0]] = true;
      }
    }

    values._transform = _transform;

    if (scriptsSubmit.length && executeSubmitScript) {
      const _REFS_ = getRefs();
      return new Promise((resolve) => {
        evalScript({
          scriptText: scriptsSubmit[0],
          extra: {
            _REFS_,
            _ENV_: structure.enviromentConfig || {},
            _BUSINESS_: { ...business, ...options },
            _OBJ_: {},
            _OBJ1_: values,
            _QUERY_: query,
            showMessage: modalErrorRef.current?.show
          },
          next: (result: NextResultType, _: any, resolveBusiness = true) => {
            const newData = { ...data, ...result };
            setScriptsChangeData(newData);

            emitControlChangeValue();

            if (resolveBusiness) resolve({ ...values, ...result });
          }
        }, true);
      });
    } else {
      return values;
    }
  }

  function onValuesChange(changeOptions: any, allValue: any) {
    let changeName = Object.keys(changeOptions)?.[0];
    let changeValue: any = Object.values(changeOptions)[0];
    let newScriptsChangeData = { ...allValue };
    let noImplementChangeScript = false;

    if (typeof changeValue === 'string' && changeValue.includes('#noImplementChangeScript')) {
      noImplementChangeScript = true;
      changeValue = changeValue.split('#noImplementChangeScript')[0];
      newScriptsChangeData[changeName] = changeValue;
    }

    if (linkFiledList.current.includes(changeName)) {
      //  数据联动组件改变
      let bindList: any[] = cacheFiledList.current[changeName] || [];
      let combineValues = {};

      if (Array.isArray(changeValue)) {
        bindList?.forEach((element) => {
          combineValues[element.name] = changeValue.reduce((all: string, next: object, index: number) => {
            return (all + (next?.[element.showFiled] || '-') + (index === changeValue.length - 1 ? '' : ' '));
          }, '');
        });

        Object.assign(newScriptsChangeData, combineValues);
      } else if (typeof changeValue === 'object') {
        bindList?.forEach((element) => {
          combineValues[element.name] = changeValue[element.showFiled];
        });

        Object.assign(newScriptsChangeData, { [changeName]: changeValue.value }, combineValues);

        // 处理select没关联的时候 传过来的对象不需要 直接取value值
        changeOptions = { [changeName]: changeValue.value };
      }

    } else if (selectNameList.current.includes(changeName)) {
      Object.assign(newScriptsChangeData, { [changeName]: changeValue.value });

      // 处理select没关联的时候 传过来的对象不需要 直接取value值
      changeOptions = { [changeName]: changeValue.value };
    }

    if (linkQueryList.current.includes(changeName)) {
      //  数据联动组件改变
      let bindList: string[] = [];
      let combineValues = {};

      const findBindList = (arr: Array<{ name: string; }>) => {
        arr.forEach(item => {
          bindList = bindList.concat(item.name);

          const nextBind = cacheQueryList.current[item.name];
          if (nextBind) findBindList(nextBind);
        });
      };

      findBindList(cacheQueryList.current[changeName] || []);

      bindList?.forEach((element) => {
        combineValues[element] = { value: changeValue, [clearFlag]: true };
      });

      Object.assign(
        newScriptsChangeData,
        bindList?.reduce((next: any, cur) => {
          next[cur] = [];
          return next;
        }, {})
      );

      // setSendData((prev: any) => ({ ...prev, ...combineValues }));
    }

    if (linkLovList.current.includes(changeName)) {
      let bindList: any[] = cacheLovList.current[changeName] || [];
      let combineValues = {};

      bindList?.forEach((element) => {
        combineValues[element.name] = { value: changeValue, [clearFlag]: true };
      });

      // setSendData((prev: any) => ({ ...prev, ...combineValues }));
    }

    if (linkTableList.current.includes(changeName)) {
      let bindList: any[] = cacheTableList.current[changeName] || [];
      let combineValues = {};

      bindList?.forEach((element) => {
        combineValues[element.name] = { value: changeValue, [clearFlag]: true };
      });

      // setSendData((prev: any) => ({ ...prev, ...combineValues }));
    }

    // lov 长度1 且0为空对象
    if (Array.isArray(changeValue)
      && changeValue.length === 1
      && Object.keys(changeValue[0]).length === 0) {
      Object.assign(newScriptsChangeData, { [changeName]: undefined });
    }

    setScriptsChangeData(newScriptsChangeData);
    form.setFieldsValue(newScriptsChangeData);

    if (!noImplementChangeScript) implementScriptsChange(changeOptions);
  }

  // 通知控件改变值
  function emitControlChangeValue() {
    form.setFieldsValue(scriptsChangeDataRef.current);

    for (let k in controlRefs.current) {
      if (controlRefs.current[k]?.setData) {
        controlRefs.current[k]!.setData!(scriptsChangeDataRef.current[k]);
      }
    }
  }

  // 非表单控件 valuesChange
  function notFormControl(id: string, data: any, isButtonChange?: boolean, changeTableKey?: string) {

    if (!isButtonChange) {
      setScriptsChangeData({
        [id]: data
      });

      emitControlChangeValue();

      if (changeTableKey) {
        implementScriptsChange(
          { [id]: data },
          { [changeTableKey]: data }
        );
      } else {
        implementScriptsChange({ [id]: data });
      }
    } else {
      setScriptsChangeData({
        ...data
      });
      emitControlChangeValue();
    }
  }

  // 处理modal
  function showModalForm(options: ShowModalOptionsType, changeId?: string) {
    modalFormRef.current?.show({
      ...options,
      initValue: {
        ...scriptsChangeDataRef.current,
        ...options.initValue
      }
    }, changeId);
  }

  function renderControl(item: ControlProps) {
    // 脚本组件 不渲染具体dom
    if (item.type === ControlType.SCRIPT_CHANGE
      || item.type === ControlType.SCRIPT_LOAD
      || item.type === ControlType.SCRIPT_SUBMIT
      || item.type === ControlType.SCRIPT_INTERCEPTORS
      || item.type === ControlType.SCRIPT_BEFORE) {
      return null;
    }

    const Control: any = controlMap[item.type];
    const options: any = { disabled: disabled || undefined, key: item.id, _id: item.id, ...item.options };
    const currActionFiled = getActionFiled(controlExtraOptions, item);

    // 脚本控制disabled
    if (typeof currActionFiled.disabled === 'boolean') {
      if (currActionFiled.disabledExcludes && includesControl(currActionFiled.disabledExcludes, item)) {
        options.disabled = !currActionFiled.disabled;
      } else {
        options.disabled = currActionFiled.disabled;
      }
    }

    // 字段隐藏 跳过 hideFields
    if (typeof currActionFiled.hide === 'boolean') {
      if (currActionFiled.hide) {
        if (currActionFiled.hideExcludes) {
          if (!includesControl(currActionFiled.hideExcludes, item)) {
            return null;
          }
        } else {
          return null;
        }
      } else {
        if (currActionFiled.hideExcludes && includesControl(currActionFiled.hideExcludes, item)) {
          return null;
        }
      }
    }

    // table
    if (item.type === 'table') {
      if (!originalColumns.current[options.name]) {
        originalColumns.current[options.name] = options.tableProps!.columns;
      }

      options.tableProps!.columns = originalColumns.current[options.name].filter(column => {
        const id = options.name + '#' + column.dataIndex;
        const currActionFiled = controlExtraOptions[id] || {};

        const hide = typeof currActionFiled.hide === 'boolean' ? currActionFiled.hide : false;

        // 处理disabled
        if (!hide) {
          if (currActionFiled.disabled) {
            column.disabled = true;
          } else if (currActionFiled.disabled === false) {
            if (!options.editColumns) options.editColumns = [];
            options.editColumns.push(column.dataIndex);
            column.disabled = false;
          }
        }

        return !hide;
      });
    }

    // 处理rules
    const _rules = JSON.parse(JSON.stringify(rules));
    if (item.type === 'upload') {
      _rules[0].message = window.$app.t('pleaseUpload') + item.options?.formItemProps?.[localStorage.i18nextLng === 'en' ? 'labelEn' : 'label'];
    }

    // 处理required
    if (typeof currActionFiled.required === 'boolean') {
      if (currActionFiled.requiredExcludes && includesControl(currActionFiled.requiredExcludes, item)) {
        if (options.formItemProps) {
          options.formItemProps.required = !currActionFiled.required;
          options.formItemProps.rules = currActionFiled.required ? null : _rules;
        }
      } else {
        if (options.formItemProps) {
          options.formItemProps.required = currActionFiled.required;
          options.formItemProps.rules = currActionFiled.required ? _rules : null;
        }
      }
    } else {
      if (options?.formItemProps?.required) {
        options.formItemProps.rules = _rules;
      } else if (options.formItemProps?.required === false) {
        options.formItemProps?.rules?.forEach((item: RuleObject) => {
          item.required = false;
        });
      }
    }

    let initialValue = data?.[options.formItemProps?.name || options?.name || item.id];
    if (item.type === 'datePicker') {
      if (initialValue) {
        initialValue = initialValue;
      } else if (!initialValue && item.options?.datePickerProps?.isInitialValue) {
        initialValue = moment().format(item.options?.datePickerProps?.format as string);
      }
    }

    return (
      <Control
        {...options}
        validateRequired={validateRequired}
        onValuesChange={notFormControl}
        ref={(ref: ControlRefProps) => (controlRefs.current[options.formItemProps?.name || options?.name || item.id] = ref)}
        initialValue={initialValue}
        enviromentConfig={structure.enviromentConfig}
        validateFields={validateFields}
        scriptsChangeData={scriptsChangeData || {}}
        setFieldsValue={form.setFieldsValue}
        controlRefs={controlRefs.current}
        Events={Events}
        business={business}
        getCurrInterceptors={(url: string) => interceptors.current[url] || {}}
        setActionFiledMap={setControlExtraOptions}
        setScriptsChangeData={setScriptsChangeData}
        emitControlChangeValue={emitControlChangeValue}
        showModal={showModalForm}
        parentNext={parentNext}
        hideModal={() => modalFormRef.current?.hide()}
        showMessage={(options: any) => modalErrorRef.current?.show(options)}
      >
        {item.children ? createControl(item.children) : null}
      </Control>
    );
  }

  function createControl(children: ControlProps[]) {
    let buttons: ControlProps[] = [];
    const dataList: ControlProps[] = [];
    const otherList: ControlProps[] = [];

    children.forEach(item => {
      if (item.type === ControlType.BUTTON && (formatFormBtns || setFooter) && !item.parentId) {
        buttons.push(item);
      } else if (item.type === ControlType.DATA_LIST) {
        dataList.push(item);
      } else {
        otherList.push(item);
      }
    });

    if (buttons.length) {
      if (setFooter) {
        setFooter({
          footer: (
            <div className='fixBtn'>
              {buttons.map(renderControl)}
            </div>
          )
        });

        buttons = [];
      }
    }

    return (
      <>
        {buttons.length ? (
          <div className={showPageHeaderBtn ? 'formBtnGroup addRight' : 'formBtnGroup'}>
            {buttons.map(renderControl)}
          </div>
        ) : null}
        {dataList.length ? (
          <>
            <div className='custom'>
              {otherList.map(renderControl)}
            </div>
            {dataList.map(renderControl)}
          </>
        ) : otherList.map(renderControl)}
      </>
    );
  }

  const hasDataList = structureList.some(item => item.type === ControlType.DATA_LIST && item?.options?.autoHeight !== false);

  return isRender ? (
    <>
      <Form
        className={`custom ${hasDataList ? 'customHasDataList' : ''}`}
        layout='vertical'
        form={form}
        initialValues={data}
        onValuesChange={onValuesChange}
        style={{ position: 'relative' }}>
        {structureList.length ? createControl(structureList) : createControl(structure.list || [])}
      </Form>

      <ModalForm
        ref={modalFormRef}
        onValuesChange={notFormControl}
      />

      <ModalError ref={modalErrorRef} />
    </>
  ) : null;
};

export default forwardRef(View);
